﻿/*
   Copyright 2012 University of Southampton

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using uk.ac.soton.ses.DAL;

namespace uk.ac.soton.ses.layouts
{
    public abstract class XYGraphDataItemSelection
    {
        public string XSeries { get; set; }
        public string YSeries { get; set; }
        public string DataItemName { get; set; }

        public delegate void XYGraphDataItemSelectionSeriesSetter(XYGraphDataItemSelection parameterSelection, string newValue);
        public delegate string XYGraphDataItemSelectionSeriesGetter(XYGraphDataItemSelection parameterSelection);
        public static XYGraphDataItemSelectionSeriesSetter XSeriesSetter = ((data, value) => data.XSeries = value);
        public static XYGraphDataItemSelectionSeriesSetter YSeriesSetter = ((data, value) => data.YSeries = value);
        public static XYGraphDataItemSelectionSeriesGetter XSeriesGetter = (data => data.XSeries);
        public static XYGraphDataItemSelectionSeriesGetter YSeriesGetter = (data => data.YSeries);
        public bool HasXDataItem { get { return !string.IsNullOrEmpty(this.XSeries); } }
        public bool HasYDataItem { get { return !string.IsNullOrEmpty(this.YSeries); } }
    }

    public enum GraphAxis
    {
        X,
        Y
    }

    public class XYGraphFieldSelection : XYGraphDataItemSelection
    {
        public int DataItemID { get; set; }
        public int FieldNo { get; set; }
    }

    public class XYParameterGraphParameterSelection : XYGraphDataItemSelection
    {
        public string SelectionKey { get; set; }
        public XYParameterGraphParameterSelection(string selectionKey)
        {
            this.SelectionKey = selectionKey;
        }
    }

    //public class ExperimentParameterInfo
    //{
    //    public int ParameterID { get; set; }
    //    public string Series { get; set; }
    //    public string ParameterPath { get; set; }
    //    public ExperimentParameter ExperimentParameter { get; set; }
    //}

    public class XYParameterGraphExperimentParameterSelection : XYGraphDataItemSelection
    {
        public string SelectionKey { get; set; }
        public int ExperimentID { get; set; }
        public int? ParentParameterID { get; set; }
        public string ParameterIDPath { get; set; }
        public string ParameterNamePath { get; set; }
        public XYParameterGraphExperimentParameterSelection(string selectionKey)
        {
            this.SelectionKey = selectionKey;
        }
    }

    public class DelimitedDataFileInfo
    {
        //Need this for data binding as we can't just do DataFile.ID for the DataKey
        public int DataFileID { get; set; }

        //A unique name for the file, including the experiment and datafile's IDs in case multiple files from different experiments have same name
        public string UniqueName { get { return string.Format("{0}:{1}:{2}", this.DataFile.Experiment.ID, this.DataFile.ID, this.DataFile.Filename); } }

        //The data file
        public ExperimentDataFile DataFile { get; set; }

        //Data for parsing the file
        public int? StartRow { get; set; }
        public int? MaxRows { get; set; }
        public char? Delimiter { get; set; }
        public int? HeaderRow { get; set; }

        //A dictionary of fields in the parsed file
        public Dictionary<int, string> Fields { get; set; }

        //Dictionaries of requested series (series name:field no)
        public Dictionary<string, int> RequestedXFields { get; set; }
        public Dictionary<string, int> RequestedYFields { get; set; }

        //Check whether the parse attributes are valid for this file (if not, the file won't be parsed)
        public bool HasParseAttributes { get { return (this.StartRow > 0 && this.MaxRows > 0 && this.Delimiter != null); } }

        //Checks for whether there are any requested series
        public bool HasRequestedXFields { get { return this.RequestedXFields.Count > 0; } }
        public bool HasRequestedYFields { get { return this.RequestedYFields.Count > 0; } }
        public bool HasRequestedFields { get { return this.HasRequestedXFields && this.HasRequestedYFields; } }

        public DelimitedDataFileInfo(ExperimentDataFile dataFile)
        {
            this.DataFile = dataFile;
            this.DataFileID = dataFile.ID;
            this.RequestedXFields = new Dictionary<string, int>();
            this.RequestedYFields = new Dictionary<string, int>();
        }

        public delegate void DataFiles_RequestData_PropertySetter(DelimitedDataFileInfo dataitem, string newValue);
        public delegate void DataFiles_RequestData_GraphSeriesSetter(DelimitedDataFileInfo dataitem, string newKey, int newValue);

        public static DataFiles_RequestData_PropertySetter MaxRowsSetter = ((data, value) => data.MaxRows = int.Parse(value));

        public static DataFiles_RequestData_PropertySetter StartRowsSetter = ((data, value) => data.StartRow = int.Parse(value));

        public static DataFiles_RequestData_PropertySetter DelimiterSetter = ((data, value) => data.Delimiter = value[0]);

        public static DataFiles_RequestData_PropertySetter HeaderRowSetter = ((data, value) => data.HeaderRow = int.Parse(value));

        public static void XGraphSeriesSetter(DelimitedDataFileInfo data, string key, int value)
        {
            GraphSeriesSetter(data.RequestedXFields, key, value);
        }

        public static void YGraphSeriesSetter(DelimitedDataFileInfo data, string key, int value)
        {
            GraphSeriesSetter(data.RequestedYFields, key, value);
        }

        public static void GraphSeriesSetter(Dictionary<string, int> fieldDictionary, string seriesname, int fieldno)
        {
            KeyValuePair<string, int> seriesInfo;

            //Try to find an existing entry with the same field number (but possibly a different series name) and remove it
            //...this should prevent duplicate field numbers and will also handle deletion of a series (when setting the series name to "")
            bool seriesfound;
            seriesfound = DelimitedDataFileInfo.GetSeriesInfoByFieldNo(fieldDictionary, fieldno, out seriesInfo);
            if (seriesfound)
            {
                fieldDictionary.Remove(seriesInfo.Key);
            }

            if (seriesname.Length > 0)
            {
                fieldDictionary[seriesname] = fieldno;
            }
        }

        public static bool GetSeriesInfoByFieldNo(Dictionary<string, int> fieldDictionary, int fieldNo, out KeyValuePair<string, int> series)
        {
            if (fieldDictionary.Count(f => f.Value == fieldNo) == 1)
            {
                series = fieldDictionary.First(f => f.Value == fieldNo);
                return true;
            }
            else
            {
                series = new KeyValuePair<string, int>("", 0);
                return false;
            }
        }
    }

}